<script setup lang="ts">
import { computed, onMounted, reactive, ref, nextTick } from 'vue'
import {
  listPictureTagCategoryUsingGet, listPictureVoByPageUsingPost,
  listPictureVoByPageWithCacheUsingPost
} from '@/api/pictureController.ts'
import { message } from 'ant-design-vue'
import { useRouter } from 'vue-router'

// 数据
const dataList = ref([])
const total = ref(0)
const loading = ref(true)
const loadingMore = ref(false)
const hasMore = ref(true)
const retryCount = ref(0)
const maxRetries = 3

// 返回顶部按钮显示状态
const showBackToTop = ref(false)

// 搜索条件
const searchParams = reactive<API.PictureQueryRequest>({
  current: 1,
  pageSize: 12,
  sortField: 'createTime',
  sortOrder: 'descend',
})

// 搜索函数 - 添加防抖
let searchTimeout: NodeJS.Timeout | null = null
const doSearch = () => {
  if (searchTimeout) {
    clearTimeout(searchTimeout)
  }

  searchTimeout = setTimeout(() => {
    // 重置搜索条件和数据
    searchParams.current = 1
    dataList.value = []
    hasMore.value = true
    retryCount.value = 0
    fetchData()
  }, 300) // 300ms 防抖
}

// 标签和分类列表
const categoryList = ref<string[]>([])
const selectedCategory = ref<string>('all')
const tagList = ref<string[]>([])
const selectedTagList = ref<string[]>([])

// 获取标签和分类选项
const getTagCategoryOptions = async () => {
  try {
    const res = await listPictureTagCategoryUsingGet()
    if (res.data.code === 0 && res.data.data) {
      categoryList.value = res.data.data.categoryList ?? []
      tagList.value = res.data.data.tagList ?? []
    } else {
      message.error('加载分类标签失败，' + res.data.message)
    }
  } catch (error) {
    message.error('获取分类标签失败，请刷新页面重试')
  }
}

// 获取数据 - 增强错误处理和重试机制
const fetchData = async (isLoadMore = false) => {
  if (isLoadMore) {
    loadingMore.value = true
  } else {
    loading.value = true
  }

  // 转换搜索参数
  const params = {
    ...searchParams,
    tags: [],
  }
  if (selectedCategory.value !== 'all') {
    params.category = selectedCategory.value
  }
  selectedTagList.value.forEach((useTag, index) => {
    if (useTag) {
      params.tags.push(tagList.value[index])
    }
  })

  try {
    const res = await listPictureVoByPageUsingPost(params)
    if (res.data.data) {
      const newData = res.data.data.records ?? []
      const newTotal = res.data.data.total ?? 0

      if (isLoadMore) {
        // 加载更多时，追加数据并去重
        const existingIds = new Set(dataList.value.map(item => item.id))
        const uniqueNewData = newData.filter(item => !existingIds.has(item.id))
        dataList.value = [...dataList.value, ...uniqueNewData]
      } else {
        // 新搜索时，替换数据
        dataList.value = newData
      }

      total.value = newTotal

      // 检查是否还有更多数据
      const currentLoadedCount = dataList.value.length
      hasMore.value = currentLoadedCount < newTotal

      // 重置重试计数
      retryCount.value = 0

    } else {
      message.error('获取数据失败，' + res.data.message)
    }
  } catch (error) {
    console.error('获取数据失败:', error)

    // 重试机制
    if (retryCount.value < maxRetries) {
      retryCount.value++
      message.warning(`网络请求失败，正在重试... (${retryCount.value}/${maxRetries})`)

      // 延迟重试
      setTimeout(() => {
        fetchData(isLoadMore)
      }, 1000 * retryCount.value)
      return
    } else {
      message.error('网络请求失败，请检查网络连接或刷新页面重试')
    }
  } finally {
    loading.value = false
    loadingMore.value = false
  }
}

// 加载更多数据 - 添加节流
let loadMoreLock = false
const loadMore = async () => {
  if (loadingMore.value || !hasMore.value || loadMoreLock) return

  loadMoreLock = true
  try {
    searchParams.current += 1
    await fetchData(true)
  } finally {
    loadMoreLock = false
  }
}

// 预加载机制 - 当接近底部时提前加载
const preloadThreshold = 300 // 距离底部300px时开始预加载
const handleScroll = () => {
  const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
  const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight
  const clientHeight = document.documentElement.clientHeight || window.innerHeight

  // 控制返回顶部按钮显示
  showBackToTop.value = scrollTop > 400

  // 预加载：当滚动到距离底部阈值内时触发
  if (scrollTop + clientHeight >= scrollHeight - preloadThreshold) {
    loadMore()
  }
}

// 返回顶部功能
const scrollToTop = () => {
  // 使用平滑滚动
  window.scrollTo({
    top: 0,
    behavior: 'smooth'
  })
}

// 使用 Intersection Observer 优化滚动检测
let observer: IntersectionObserver | null = null
const observerTarget = ref<HTMLElement>()

const setupIntersectionObserver = () => {
  if (!('IntersectionObserver' in window)) {
    // 降级到滚动监听
    window.addEventListener('scroll', throttledScroll)
    return
  }

  observer = new IntersectionObserver(
    (entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting && hasMore.value && !loadingMore.value) {
          loadMore()
        }
      })
    },
    {
      rootMargin: '200px', // 提前200px触发
      threshold: 0.1
    }
  )

  // 延迟设置观察目标，等待DOM渲染
  nextTick(() => {
    if (observerTarget.value && observer) {
      observer.observe(observerTarget.value)
    }
  })
}

// 防抖处理滚动事件（备用方案）
let scrollTimer: NodeJS.Timeout | null = null
const throttledScroll = () => {
  if (scrollTimer) return
  scrollTimer = setTimeout(() => {
    handleScroll()
    scrollTimer = null
  }, 100)
}

const router = useRouter()
// 跳转至图片详情
const doClickPicture = (picture) => {
  router.push({
    path: `/picture/${picture.id}`,
  })
}

// 图片懒加载错误处理
const handleImageError = (event) => {
  const img = event.target
  if (!img.dataset.retried) {
    img.dataset.retried = 'true'
    // 延迟重试加载图片
    setTimeout(() => {
      img.src = img.src
    }, 2000)
  } else {
    // 设置默认图片
    img.src = '/api/placeholder/180/180'
    img.alt = '图片加载失败'
  }
}

// 手动刷新功能
const refreshData = () => {
  searchParams.current = 1
  dataList.value = []
  hasMore.value = true
  retryCount.value = 0
  fetchData()
}

onMounted(() => {
  getTagCategoryOptions()
  fetchData()
  setupIntersectionObserver()
  // 添加滚动监听来控制返回顶部按钮
  window.addEventListener('scroll', throttledScroll)
})

// 组件卸载时清理
import { onUnmounted } from 'vue'
onUnmounted(() => {
  if (observer) {
    observer.disconnect()
  }
  window.removeEventListener('scroll', throttledScroll)
  if (scrollTimer) {
    clearTimeout(scrollTimer)
  }
  if (searchTimeout) {
    clearTimeout(searchTimeout)
  }
})

// 计算属性：显示加载状态文本
const loadingText = computed(() => {
  if (retryCount.value > 0) {
    return `正在重试加载... (${retryCount.value}/${maxRetries})`
  }
  return '正在加载更多精美图片...'
})
</script>

<template>
  <div id="HomePage">
    <!-- 搜索框 -->
    <div class="search-bar">
      <a-input-search
        placeholder="从海量图片中搜索"
        v-model:value="searchParams.searchText"
        enter-button="搜索"
        size="large"
        @search="doSearch"
        :loading="loading"
      />
    </div>

    <!-- 分类 + 标签 -->
    <a-tabs v-model:activeKey="selectedCategory" @change="doSearch">
      <a-tab-pane key="all" tab="全部" />
      <a-tab-pane v-for="category in categoryList" :key="category" :tab="category" />
    </a-tabs>

    <div class="tag-bar">
      <span style="margin-right: 8px">标签：</span>
      <a-space :size="[0, 8]" wrap>
        <a-checkable-tag
          v-for="(tag, index) in tagList"
          :key="tag"
          v-model:checked="selectedTagList[index]"
          @change="doSearch"
        >
          {{ tag }}
        </a-checkable-tag>
      </a-space>
    </div>

    <!-- 图片列表 -->
    <a-list
      :grid="{ gutter: 16, xs: 1, sm: 2, md: 3, lg: 4, xl: 5, xxl: 6 }"
      :data-source="dataList"
      :loading="loading"
    >
      <template #renderItem="{ item: picture, index }">
        <a-list-item style="padding: 0">
          <!-- 单张图片 -->
          <a-card
            hoverable
            @click="doClickPicture(picture)"
            :class="{ 'fade-in': true }"
            :style="{ 'animation-delay': `${(index % 12) * 50}ms` }"
          >
            <template #cover>
              <div class="image-container">
                <img
                  style="height: 180px; object-fit: cover; width: 100%; transition: transform 0.3s ease;"
                  :alt="picture.name"
                  :src="picture.url"
                  loading="lazy"
                  @error="handleImageError"
                  @load="(e) => e.target.classList.add('loaded')"
                />
                <div class="image-overlay">
                  <div class="image-actions">
                    <a-button type="primary" ghost size="small">
                      查看详情
                    </a-button>
                  </div>
                </div>
              </div>
            </template>
            <a-card-meta :title="picture.name">
              <template #description>
                <a-flex>
                  <a-tag color="green">
                    {{ picture.category ?? '默认' }}
                  </a-tag>
                  <a-tag v-for="tag in picture.tags" :key="tag">
                    {{ tag }}
                  </a-tag>
                </a-flex>
              </template>
            </a-card-meta>
          </a-card>
        </a-list-item>
      </template>
    </a-list>

    <!-- 加载更多区域 -->
    <div class="load-more-section">
      <div v-if="loadingMore" class="loading-more">
        <a-spin size="large" />
        <p class="loading-text">{{ loadingText }}</p>
        <div class="loading-progress">
          <div class="progress-bar">
            <div class="progress-fill"></div>
          </div>
        </div>
      </div>
      <div v-else-if="!hasMore && dataList.length > 0" class="no-more">
        <div class="no-more-icon">✨</div>
        <p class="no-more-text">你已经看完所有图片了</p>
        <p class="no-more-subtitle">试试调整筛选条件发现更多内容</p>
        <a-button type="link" @click="refreshData" class="refresh-btn">
          🔄 刷新数据
        </a-button>
      </div>
      <div v-else-if="dataList.length === 0 && !loading" class="empty-state">
        <div class="empty-icon">🔍</div>
        <p class="empty-text">没有找到相关图片</p>
        <p class="empty-subtitle">试试其他关键词或筛选条件</p>
        <a-button type="primary" @click="refreshData" class="retry-btn">
          重新搜索
        </a-button>
      </div>

      <!-- Intersection Observer 目标元素 -->
      <div ref="observerTarget" class="observer-target"></div>
    </div>

    <!-- 返回顶部按钮 -->
    <transition name="back-to-top">
      <div
        v-if="showBackToTop"
        class="back-to-top-btn"
        @click="scrollToTop"
        title="返回顶部"
      >
        <svg viewBox="0 0 24 24" class="back-to-top-icon">
          <path fill="currentColor" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/>
        </svg>
      </div>
    </transition>
  </div>
</template>

<style scoped>
#HomePage .search-bar {
  max-width: 480px;
  margin: 0 auto 16px;
}

.tag-bar {
  margin-bottom: 16px;
}

/* 图片卡片动画 */
.fade-in {
  animation: fadeInUp 0.6s ease-out both;
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* 图片容器样式 */
.image-container {
  position: relative;
  overflow: hidden;
  border-radius: 6px 6px 0 0;
}

.image-container:hover img {
  transform: scale(1.05);
}

.image-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.image-container:hover .image-overlay {
  opacity: 1;
}

.image-actions {
  text-align: center;
}

/* 图片加载效果 */
.image-container img {
  background: #f5f5f5;
  background-image: linear-gradient(45deg, #f0f0f0 25%, transparent 25%),
  linear-gradient(-45deg, #f0f0f0 25%, transparent 25%),
  linear-gradient(45deg, transparent 75%, #f0f0f0 75%),
  linear-gradient(-45deg, transparent 75%, #f0f0f0 75%);
  background-size: 20px 20px;
  background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
}

.image-container img.loaded {
  background: none;
}

/* 加载更多区域 */
.load-more-section {
  text-align: center;
  padding: 40px 0;
  min-height: 120px;
}

.loading-more {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

.loading-text {
  color: #666;
  font-size: 16px;
  font-weight: 500;
  margin: 0;
}

.loading-progress {
  width: 200px;
}

.progress-bar {
  height: 3px;
  background: #f0f0f0;
  border-radius: 2px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #1890ff, #40a9ff);
  border-radius: 2px;
  animation: progressLoading 2s ease-in-out infinite;
}

@keyframes progressLoading {
  0% {
    width: 0%;
    margin-left: 0%;
  }
  50% {
    width: 75%;
    margin-left: 25%;
  }
  100% {
    width: 0%;
    margin-left: 100%;
  }
}

.no-more, .empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 40px 20px;
}

.no-more-icon, .empty-icon {
  font-size: 48px;
  margin-bottom: 8px;
  animation: bounce 2s infinite;
}

@keyframes bounce {
  0%, 20%, 50%, 80%, 100% {
    transform: translateY(0);
  }
  40% {
    transform: translateY(-10px);
  }
  60% {
    transform: translateY(-5px);
  }
}

.no-more-text, .empty-text {
  font-size: 18px;
  font-weight: 600;
  color: #333;
  margin: 0;
}

.no-more-subtitle, .empty-subtitle {
  font-size: 14px;
  color: #666;
  margin: 0;
}

.refresh-btn, .retry-btn {
  margin-top: 16px;
}

.observer-target {
  height: 1px;
  margin-top: 20px;
}

/* 返回顶部按钮样式 */
.back-to-top-btn {
  position: fixed;
  right: 30px;
  bottom: 50px;
  width: 50px;
  height: 50px;
  background: #808383;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 1000;
  box-shadow: 0 4px 12px rgba(24, 144, 255, 0.3);
  transition: all 0.3s ease;
  user-select: none;
}

.back-to-top-btn:hover {
  background: #40a9ff;
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(24, 144, 255, 0.4);
}

.back-to-top-btn:active {
  transform: translateY(0);
  box-shadow: 0 2px 8px rgba(24, 144, 255, 0.3);
}

.back-to-top-icon {
  width: 24px;
  height: 24px;
  color: white;
  transition: transform 0.2s ease;
}

.back-to-top-btn:hover .back-to-top-icon {
  transform: translateY(-1px);
}

/* 返回顶部按钮动画 */
.back-to-top-enter-active,
.back-to-top-leave-active {
  transition: all 0.3s ease;
}

.back-to-top-enter-from {
  opacity: 0;
  transform: translateY(20px) scale(0.8);
}

.back-to-top-leave-to {
  opacity: 0;
  transform: translateY(20px) scale(0.8);
}

/* 响应式优化 */
@media (max-width: 768px) {
  .loading-text {
    font-size: 14px;
  }

  .loading-progress {
    width: 150px;
  }

  .no-more-text, .empty-text {
    font-size: 16px;
  }

  .back-to-top-btn {
    right: 20px;
    bottom: 30px;
    width: 45px;
    height: 45px;
  }

  .back-to-top-icon {
    width: 20px;
    height: 20px;
  }
}

/* 暗色主题适配 */
@media (prefers-color-scheme: dark) {
  .image-container img {
    background: #1f1f1f;
    background-image: linear-gradient(45deg, #2a2a2a 25%, transparent 25%),
    linear-gradient(-45deg, #2a2a2a 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #2a2a2a 75%),
    linear-gradient(-45deg, transparent 75%, #2a2a2a 75%);
  }

  .progress-bar {
    background: #2a2a2a;
  }

  .back-to-top-btn {
    background: #177ddc;
    box-shadow: 0 4px 12px rgba(23, 125, 220, 0.3);
  }

  .back-to-top-btn:hover {
    background: #1890ff;
    box-shadow: 0 6px 20px rgba(23, 125, 220, 0.4);
  }
}
</style>
